﻿using System.Diagnostics;
using System.Net.Mail;
using Kaleida.ServiceMonitor.Framework;
using Kaleida.ServiceMonitor.Model.Runtime;
using Kaleida.ServiceMonitor.Operations.PreparedRequests;
using Kaleida.ServiceMonitor.Operations.ResponseHandlers;
using NUnit.Framework;

namespace Kaleida.UnitTests.Model.Runtime
{
    [TestFixture]
    public class CompiledScriptTests
    {
        [Test]
        public void TestBuildSummaryDefault()
        {
            var script = new CompiledScript("MyScript");

            const string expected = "Module 'MyScript':\r\n" +
                                    "  0 operations performed in Round-Robin order, " +
                                    "with 1000 ms between each invocation\r\n" +
                                    "  The maximum age of any error is 100 days.\r\n" +
                                    "  Colour thresholds: Not monitoring: Gray, 0 failures: " +
                                    "LightGreen, 1 failure: Yellow, 2 to 9 failures: Orange, " +
                                    "10 to 99 failures: LightCoral, 100 or more failures: Crimson, otherwise White\r\n\r\n";

            string summary = script.BuildSummary();
            Trace.WriteLine(summary);
            Assert.AreEqual(expected, summary);
        }

        [Test]
        public void TestBuildSummaryWhenPollIntervalModified()
        {
            var script = new CompiledScript("MyScript");
            script.Root.ScriptModule.PollInterval = new Duration(1.5, "days");

            TestSummaryContains(script, "with 1.5 days between each invocation");
        }

        [Test]
        public void TestBuildSummaryWhenColoursModified()
        {
            var script = new CompiledScript("MyScript");
            script.Root.ScriptModule.ColourationStrategy = StateColourationStrategy.Parse("0 failures green, 1-5 failures yellow, 6+ failures red");

            TestSummaryContains(script, "Colour thresholds: Not monitoring: Gray, 0 failures: Green, 1 to 5 failures: Yellow, 6 or more failures: Red, otherwise White");
        }

        [Test]
        public void TestBuildSummaryWhenMaxErrorAgeModified()
        {
            var script = new CompiledScript("MyScript");
            script.Root.ScriptModule.MaximumErrorAge = new Duration(24, "hours");

            TestSummaryContains(script, "The maximum age of any error is 24 hours");
        }

        [Test]
        public void TestBuildSummaryWhenOrderIsRandom()
        {
            var script = new CompiledScript("MyScript");
            script.Root.ScriptModule.ExecutionOrder = new RandomOperationOrder();

            TestSummaryContains(script, "performed in Random order");
        }


        [Test]
        public void TestBuildSummaryWhenThresholdEmailSet()
        {
            var script = new CompiledScript("MyScript");

            script.Root.ScriptModule.EmailOnThresholdChangeRecipients = new[] {new MailAddress("bob@example.com")};
            TestSummaryContains(script, "When the monitor colour changes, emails will be sent to: bob@example.com");

            script.Root.ScriptModule.EmailOnThresholdChangeRecipients = new[] { new MailAddress("bob@example.com"), new MailAddress("joe@example.com") };
            TestSummaryContains(script, "When the monitor colour changes, emails will be sent to: bob@example.com; joe@example.com");
        }

        [Test]
        public void TestBuildSummaryWhenEmailSummarySet()
        {
            var script = new CompiledScript("MyScript");

            script.Root.ScriptModule.EmailSummarySchedule = new EmailSummarySchedule(new[]
                                                                                         {
                                                                                             new MailAddress("bob@example.com")
                                                                                         }, new[]
                                                                                                {
                                                                                                    new ScheduledTime(8, 15),
                                                                                                    new ScheduledTime(20, 30)
                                                                                                });
            TestSummaryContains(script, "At 08:15, 20:30 every day, a summary email will be sent to: bob@example.com");
        }

        [Test]
        public void TestBuildSummaryWhenOperationsPresent()
        {
            var script = new CompiledScript("MyScript");

            TestSummaryContains(script, "0 operations performed");

            script.Root.ScriptModule.Operations.Add(new Operation(new Ping("localhost"), new DoNothing(), new CurrentWindowsUser()));
            TestSummaryContains(script, "1 operation performed");

            script.Root.ScriptModule.Operations.Add(new Operation(new Ping("localhost"), new DoNothing(), new CurrentWindowsUser()));
            TestSummaryContains(script, "2 operations performed");
        }

        [Test]
        public void TestBuildSummaryWithNestedGroups()
        {
            var root = new CompiledNode(
                new CompiledGroup(new[]
                                      {
                                          new CompiledNode(new CompiledScriptModule("Group1")
                                                               {
                                                                   PollInterval = new Duration(1, "hr"),
                                                                   ColourationStrategy = StateColourationStrategy.Parse("0+ failures green")
                                                               }),
                                          new CompiledNode(
                                              new CompiledGroup(new[]
                                                                    {
                                                                        new CompiledNode(new CompiledScriptModule("Group1a")
                                                                                             {
                                                                                                 PollInterval = new Duration(2, "hr"),
                                                                                                 ColourationStrategy = StateColourationStrategy.Parse("0+ failures yellow")
                                                                                             }),
                                                                        new CompiledNode(new CompiledScriptModule("Group1b")
                                                                                             {
                                                                                                 PollInterval = new Duration(3, "hr"),
                                                                                                 ColourationStrategy = StateColourationStrategy.Parse("0+ failures orange")
                                                                                             })
                                                                    })),
                                          new CompiledNode(new CompiledScriptModule("Group2")
                                                               {
                                                                   PollInterval = new Duration(4, "hr"),
                                                                   ColourationStrategy = StateColourationStrategy.Parse("0+ failures red")
                                                               })
                                      }
                    ));

            var script = new CompiledScript("MyScript", root);

            const string expected = "Script contains 4 nested modules:\r\n" +
                                    "\r\n" +
                                    "Module 'Group1':\r\n" +
                                    "  0 operations performed in Round-Robin order, with 1 hr between each invocation\r\n" +
                                    "  The maximum age of any error is 100 days.\r\n" +
                                    "  Colour thresholds: Not monitoring: Gray, 0 or more failures: Green, otherwise White\r\n" +
                                    "\r\n" +
                                    "Module 'Group1a':\r\n" +
                                    "  0 operations performed in Round-Robin order, with 2 hr between each invocation\r\n" +
                                    "  The maximum age of any error is 100 days.\r\n" +
                                    "  Colour thresholds: Not monitoring: Gray, 0 or more failures: Yellow, otherwise White\r\n" +
                                    "\r\n" +
                                    "Module 'Group1b':\r\n" +
                                    "  0 operations performed in Round-Robin order, with 3 hr between each invocation\r\n" +
                                    "  The maximum age of any error is 100 days.\r\n" +
                                    "  Colour thresholds: Not monitoring: Gray, 0 or more failures: Orange, otherwise White\r\n" +
                                    "\r\n" +
                                    "Module 'Group2':\r\n" +
                                    "  0 operations performed in Round-Robin order, with 4 hr between each invocation\r\n" +
                                    "  The maximum age of any error is 100 days.\r\n" +
                                    "  Colour thresholds: Not monitoring: Gray, 0 or more failures: Red, otherwise White\r\n" +
                                    "\r\n";

            string summary = script.BuildSummary();
            Trace.WriteLine(summary);
            Assert.AreEqual(expected, summary);
        }

        private static void TestSummaryContains(CompiledScript script, string expectedText)
        {
            string summary = script.BuildSummary();
            Trace.WriteLine(summary);
            Assert.IsTrue(summary.Contains(expectedText), "Expected summary to contain '{0}'", expectedText);
        }
    }
}
